using System;
using System.Collections;
using System.Diagnostics;
using NUnit.Framework;
using ActiveRecord;


namespace ActiveRecord.Tests
{
   public partial class Tests
	{
      [Test]
      [Category("Associations")]
      [Category("HasMany_BelongsTo")]
		public void HasMany_BelongsToAssociations() {
         Customer c = new Customer();
         Order o = new Order();
         c["name"] = "travis";
         c.Save();
         Console.WriteLine("Customer record: " + c);
         o["customer_id"] = c["id"];
         o.Save();
         //Console.WriteLine(o.ToString());
         ActiveTable tblCust = o.GetAssociated("customers");
         Assert.IsNotNull(tblCust, "customers table was null");
         Assert.IsTrue(tblCust.Length > 0, "customers table had no records");
         ActiveTable tblOrders = c.GetAssociated("orders");
         Assert.IsNotNull(tblOrders, "orders table was null");
         Assert.IsTrue(tblOrders.Length > 0, "orders table had no records");
         //Console.WriteLine("tblOrders: " + (tblOrders == null ? "null" : tblOrders.ToString()));
         Assert.AreEqual(tblCust[0]["name"], c["name"], "simple association didn't work");
         Assert.AreEqual(tblOrders[0]["id"], o["id"], "simple association didn't work");
         c.Delete();
         o.Delete();
      }
      
      [Test]
      [Category("Associations")]
		public void HasOne() {
         Customer c = new Customer();
         c["name"] = "Travis";
         SalesRep sr = new SalesRep();
         sr.Save();
         c["sales_rep_id"] = sr["id"];
         c.Save();
         Console.WriteLine("Expected SQL: select * from sales_reps where id = " + c["sales_rep_id"]);
         ActiveTable tblSalesReps = c.GetAssociated("sales_reps");
         Assert.IsNotNull(tblSalesReps, "sales_reps table was null");
         Assert.AreEqual(1, tblSalesReps.Length , "sales_reps table should have 1 record");
         Assert.AreEqual(tblSalesReps[0]["id"], sr["id"], "HasOne association didn't work"); 
         
      }
      
      [Test]
      [Category("Associations")]
      [Category("ManyToMany")]
		public void HasAndBelongsToMany() {
         Developer d = new Developer();
         Project p1 = new Project();
         Project p2 = new Project();
         manyToManyTest(d, p1, p2, "HasAndBelongsToMany");
         /*
         Developer d = new Developer();
         d.Save();
         Project p1 = new Project();
         Project p2 = new Project();
         p1["name"] = "First Project";
         p2["name"] = "Second Project";
         p1.Save(); p2.Save();
         
         ActiveRecordBase.NonQuery(string.Format(
            "insert into developers_projects (developer_id, project_id) values ({0}, {1})", d["id"], p1["id"]));
         ActiveRecordBase.NonQuery(string.Format(
            "insert into developers_projects (developer_id, project_id) values ({0}, {1})", d["id"], p2["id"]));

         ActiveTable devProjects = d.GetAssociated("projects");
         Assert.IsNotNull(devProjects, "devProjects table was null");
         Assert.AreEqual(2, devProjects.Length, "devProjects didn't have 2 records.  Projects found " + devProjects.Length);
         Assert.AreEqual(p1["name"], devProjects[0]["name"], "devProjects first project didn't have right name");
         
         ActiveTable projDevs = p1.GetAssociated("developers");
         Assert.IsNotNull(projDevs, "projDevs table was null");
         Assert.AreEqual(1, projDevs.Length, "projDevs didn't have 1 record.  Projects found " + projDevs.Length);
         Assert.AreEqual(d["id"], projDevs[0]["id"], "projDevs first dev didn't have right id");
         
         ActiveRecordBase.NonQuery("delete from developers_projects where developer_id = " + d["id"]);
         p1.Delete();p2.Delete();d.Delete();
         */
      }
      
      [Test]
      [Category("Associations")]
      [Category("ManyToMany")]
      [Category("HABTMThrough")]
		public void HasAndBelongsToManyThrough() {
         Developer2 d = new Developer2();
         Project2 p1 = new Project2();
         Project2 p2 = new Project2();
         
         manyToManyTest(d, p1, p2, "HasAndBelongsToManyThrough");
         /*
         Developer2 d = new Developer2();
         d.Save();
         Project2 p1 = new Project2();
         Project2 p2 = new Project2();
         p1["name"] = "First Project";
         p2["name"] = "Second Project";
         p1.Save(); p2.Save();
         
         ActiveRecordBase.NonQuery(string.Format(
            "insert into developers_projects (developer_id, project_id) values ({0}, {1})", d["id"], p1["id"]));
         ActiveRecordBase.NonQuery(string.Format(
            "insert into developers_projects (developer_id, project_id) values ({0}, {1})", d["id"], p2["id"]));

         ActiveTable devProjects = d.GetAssociated("projects");
         Assert.IsNotNull(devProjects, "(Through) devProjects table was null");
         Assert.AreEqual(2, devProjects.Length, "(Through) devProjects didn't have 2 records.  Projects found " + devProjects.Length);
         Assert.AreEqual(p1["name"], devProjects[0]["name"], "(Through) devProjects first project didn't have right name");
         
         ActiveTable projDevs = p1.GetAssociated("developers");
         Assert.IsNotNull(projDevs, "(Through) projDevs table was null");
         Assert.AreEqual(1, projDevs.Length, "(Through) projDevs didn't have 1 record.  Projects found " + projDevs.Length);
         Assert.AreEqual(d["id"], projDevs[0]["id"], "(Through) projDevs first dev didn't have right id");
         
         ActiveRecordBase.NonQuery("delete from developers_projects where developer_id = " + d["id"]);
         p1.Delete();p2.Delete();d.Delete();
         */
      }
 
      [Test]
      [Category("Associations")]
      [Category("ManyToMany")]
      [Category("HABTMThrough")]
		[Category("ManyToManyEager")]
      public void HasAndBelongsToManyThroughEager() {
         Developer4 d = new Developer4();
         Project4 p1 = new Project4();
         Project4 p2 = new Project4();
         
         manyToManyTest(d, p1, p2, "HasAndBelongsToManyThroughEager");
      }
      
      [Test]
      [Category("Associations")]
      [Category("ManyToMany")]
      [Category("MTMThrough")]
      public void ManyToManyThrough() {
         Developer3 d = new Developer3();
         Project3 p1 = new Project3();
         Project3 p2 = new Project3();
         
         manyToManyTest(d, p1, p2, "ManyToManyThrough");
      }

      [Test]
      [Category("Associations")]
      [Category("ManyToMany")]
      [Category("Eager")]
      [Category("ManyToManyEager")]
      public void ManyToManyThroughEager() {
         Developer5 d = new Developer5();
         Project5 p1 = new Project5();
         Project5 p2 = new Project5();
         
         manyToManyTest(d, p1, p2, "ManyToManyThroughEager");
      }
		
      protected void manyToManyTest(ActiveRecordBase d, ActiveRecordBase p1, ActiveRecordBase p2, string testName) {
         d.Save();
         p1["name"] = "First Project";
         p2["name"] = "Second Project";
         p1.Save(); p2.Save();
         
         ActiveRecordBase.NonQuery(string.Format(
            "insert into developers_projects (developer_id, project_id) values ({0}, {1})", d["id"], p1["id"]));
         ActiveRecordBase.NonQuery(string.Format(
            "insert into developers_projects (developer_id, project_id) values ({0}, {1})", d["id"], p2["id"]));

         ActiveTable devProjects = d.GetAssociated("projects");
         Assert.IsNotNull(devProjects, "(" + testName + ") devProjects table was null");
         Assert.AreEqual(2, devProjects.Length, "(" + testName + ") devProjects didn't have 2 records.  Projects found " + devProjects.Length);
         Assert.AreEqual(p1["name"], devProjects[0]["name"], "(" + testName + ") devProjects first project didn't have right name");
         
         ActiveTable projDevs = p1.GetAssociated("developers");
         Assert.IsNotNull(projDevs, "(" + testName + ") projDevs table was null");
         Assert.AreEqual(1, projDevs.Length, "(" + testName + ") projDevs didn't have 1 record.  Projects found " + projDevs.Length);
         Assert.AreEqual(d["id"], projDevs[0]["id"], "(" + testName + ") projDevs first dev didn't have right id");
         
         ActiveRecordBase.NonQuery("delete from developers_projects where developer_id = " + d["id"]);
         p1.Delete();p2.Delete();d.Delete();
      }
      
      [Test]
      [Category("Associations")]
      public void LazyLoad() {
         Customer c = new Customer();
         Order o = new Order();
         c["name"] = "Travis mavis";
         c.Save();
         o["customer_id"] = c["id"];
         o.Save();
         Assert.IsTrue(!o.Associations.ContainsKey("customers"), "TestLazyLoad(). o.Associations[\"customers\"] should not be present");  
         ActiveTable custs = o.GetAssociated("customers");
         Assert.IsNotNull(o.Associations["customers"], "TestLazyLoad(). o.Associations[\"customers\"] should not be null");
         Assert.AreEqual(c["id"], custs[0]["id"], "Order.GetAssociated(Customer) failed with lazy loading");
      }
      
      [Test]
      [Category("Associations")]
      [Category("Taintedness")]
      public void TaintedContent() {
         Blog b = new Blog();
         b.Save();
         Assert.IsNotNull(b[b.PrimaryKey], "TestTaintedContent(), PrimaryKey value was null after initial save");
         string sBlogname = "My Blog";
         b["name"] = sBlogname;
         b.Save();
         ActiveRecordBase b2 = Blog.FindById(typeof(Blog), b["id"]); 
         Assert.AreEqual(b2["name"], sBlogname, "TestTaintedContent(), content wasn't saved after taint and save");
      }
      
      [Test]
      [Category("Associations")]
      [Category("Taintedness")]
      public void TaintedPrimaryKey() {
         Blog b = new Blog();
         string blogname = "Hello blogosphere! - TaintedPrimaryKey";
         b["name"] = blogname;
         b.Save();
         
         Assert.IsNotNull(b[b.PrimaryKey], "TestTaintedPrimaryKey(), PrimaryKey value was null after initial save");
         Blog b2 = new Blog();
         b2.Save();
         b2[b2.PrimaryKey] = b[b.PrimaryKey];
         b2.Load();
         Assert.AreEqual(blogname, b2["name"], string.Format("TestTaintedPrimaryKey(), Blog ({0}) content wasn't refreshed after pk taint and load", b2));
      }
      
      [Test]
      [Category("Associations")]
      [Category("Taintedness")]
      [Category("TestTaintedForeignKey")]
      public void TaintedForeignKey() {
         // setup blog and save
         Blog b = new Blog();
         string blogname = "Hello blogosphere! - TaintedForeignKey";
         b["name"] = blogname;
         b.Save();
         
         // setup child post
         Post p = new Post();
         p["type_code"]  = "B";
         p["parent_id"] = b[b.PrimaryKey];
         p.Save();
         Assert.IsNotNull(p["parent_id"], "TestTaintedForeignKey(), Post.parent_id value was null after initial save");
         
         // setup new blog and adopt post, posts are eager
         Blog b2 = new Blog();
         b2.Save();
         p["parent_id"] = b2[b2.PrimaryKey];
         p.Save();
         
         // make sure that the post's blog is the second one, b2
         Console.WriteLine("expecting sql to be \"select * from blog_table where id = {0}\"", p["parent_id"]);
         ActiveRecordBase associatedBlog = p.GetAssociated("blog_table")[0];
         Console.WriteLine("associatedBlog: " + associatedBlog);
         Assert.AreEqual(b2["id"], associatedBlog["id"], "TestTaintedForeignKey(), Post.GetAssociated(blog_table) content wasn't refreshed after fk taint");
         //Console.WriteLine("associatedBlog[\"name\"].GetType(): " + associatedBlog["name"].GetType());
         Assert.IsTrue(associatedBlog["name"] == DBNull.Value, "TestTaintedForeignKey(), Post.GetAssociated(blog_table) content wasn't refreshed after fk taint");
      }
      
      [Test]
      [Category("EagerLoading")]
      [Category("Associations")]
      public void EagerLoad() {
         Blog b = new Blog();
         b.Save();
         Assert.IsTrue(b.Columns.Length > 0, "eager loading, didn't load anything");
         //Console.WriteLine("EagerLoading: Blog");
         //Console.WriteLine(b);
         Post p1 = new Post();
         p1["parent_id"] = b["id"];
         Post p2 = new Post();
         p2["parent_id"] = b["id"];
         p1.Save(); p2.Save();
         
         ActiveTable assocBlogs = p1.Associations["blog_table"];
         Assert.AreEqual(1, assocBlogs.Length, "failed to eager load post blogs");
         b.ReLoad();
         ActiveTable assocPosts = b.Associations["post_table"];
         Assert.AreEqual(2, assocPosts.Length, "failed to eager load blogs posts");
         
         Assert.AreEqual(b["id"], assocBlogs[0]["id"], "post associated blog_table, didn't load id");
         Assert.AreEqual(p1["id"], assocPosts[0]["id"], "blog associated post_table, didn't load id");
      }
      
      [Test]
      [Category("Associations")]
      [Category("Taintedness")]
      [Category("EagerLoading")]
      [Category("TaintEagerLoad")]
      public void TaintEagerLoad() {
         Blog b = new Blog();
         b.Save();
         Post p = new Post();
         p["type_code"] = "B";
         p["parent_id"] = b["id"];
         p.Save();
         Blog b2 = new Blog();
         b2.Save();
         p["parent_id"] = b2["id"]; // move post to a different blog (taint fk)
         p.Save();
         // have to force reload becuase this association has already been loaded and the blog has not been tainted 
         ActiveTable posts = b2.GetAssociated("post_table", true); 
         Assert.AreEqual(1, posts.Length, "assoc post table should have one record");
         Console.WriteLine("b2.Associations: " + string.Join(",", b2.AssociationTables));
         Assert.IsNotNull(posts, "b2.GetAssociated(post_table) was null");
         Console.WriteLine("posts[0]: " + posts[0]);
         Assert.AreEqual(p["id"], posts[0]["id"], "Blog.GetAssociated(Post) failed with optimistic loading");
      }
      
      /*
      [Test]
      [Category("Associations")]
      public void HasAndBelongsToAssn() {
         Developer d = new Developer();
         d["first_name"] = "Travis";
         d["last_name"] = "Staloch";
         d.Save();
         
         Project proj = new Project();
         proj["name"] = "ActiveRecordSharp";
         proj["developer_id"] = d["id"];
         proj.Save();
         
         ActiveTable projDevs = proj.GetAssociated("developers");
         Assert.AreEqual(1, projDevs.Length, "Didn't get any developers for this project");
         Assert.AreEqual(d["id"], projDevs[0]["developer_id"], "Associated developer is not the same developer");
         
      }
      */
      
      
   }
   
   
   
}